//#define USE_CALLSTACK_STAT

#ifdef USE_CALLSTACK_STAT
#include "ap/ap_dlstat_callstack.h"
#endif

#define AP_CHECK_CURRENT_PROCESSOR

// operators
template <class CH> __INLINE 
dsTSTRING<CH> operator + (const dsTSTRING<CH> &a, const dsTSTRING<CH> &b)
{
   dsTSTRING<CH> res(a);
   res += b;
   return res;
}

template <class CH> __INLINE
dsTSTRING<CH> operator + (const CH *a, const dsTSTRING<CH> &b)
{
   if (!a) {
      ASSERT(a);
      a = "";
   }
   dsTSTRING<CH> res(a, -1, b.Length());
   res += b;
   return res;
}

template <class CH> __INLINE
dsTSTRING<CH> operator + (const dsTSTRING<CH> &a, const CH *b)
{
   if (!b) {
      ASSERT(b);
      b = "";
   }
   dsTSTRING<CH> res(a);
   res += b;
   return res;
}

template <class CH> __INLINE
dsTSTRING<CH> operator + (CH a, const dsTSTRING<CH> &b)
{
   dsTSTRING<CH> res(b.Length() + 1);
   res += a;
   res += b;
   return res;
}

template <class CH> __INLINE
dsTSTRING<CH> operator + (const dsTSTRING<CH> &a, CH b)
{
   dsTSTRING<CH> res(a);
   res += b;
   return res;
}


__INLINE bool operator < (const char *a, const dsSTRING &b)
{
   return strcmp(a, b.CStr()) < 0;
}

__INLINE bool operator > (const char *a, const dsSTRING &b)
{
   return strcmp(a, b.CStr()) > 0;
}

__INLINE bool operator <= (const char *a, const dsSTRING &b)
{
   return strcmp(a, b.CStr()) <= 0;
}

__INLINE bool operator >= (const char *a, const dsSTRING &b)
{
   return strcmp(a, b.CStr()) >= 0;
}

__INLINE bool operator == (const char *a, const dsSTRING &b)
{
   return strcmp(a, b.CStr()) == 0;
}

__INLINE bool operator != (const char *a, const dsSTRING &b)
{
   return strcmp(a, b.CStr()) != 0;
}

//
// class dsTSTRING implementation
//

/*************************************************************
* dsTSTRING::dsTSTRING ()
*
*************************************************************/
template <class CH> FORCE_INLINE dsTSTRING<CH>::dsTSTRING() : pBuffer(NULL)
{
   AP_CHECK_CURRENT_PROCESSOR;
   UnsafeInitEmpty();
   return;
}

/*************************************************************
* dsTSTRING::dsTSTRING ()
*
*************************************************************/
//template <class CH> FORCE_INLINE dsTSTRING<CH>::dsTSTRING(apSUPPRESS_PROCESSOR_LOCK) : pBuffer(NULL)
//{
//   UnsafeInitEmpty();
//   return;
//}

/*************************************************************
* dsTSTRING::dsTSTRING ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH>::dsTSTRING(int maxStrLen) : pBuffer(NULL)
{
   pBuffer = AllocBuffer(maxStrLen, 0);
   return;
}

/*************************************************************
* dsTSTRING::dsTSTRING ()
*
*************************************************************/
template <class CH> FORCE_INLINE dsTSTRING<CH>::dsTSTRING(const dsTSTRING &str) : pBuffer(NULL)
{
   AttachBuffer(str.pBuffer);
   return;
}

/*************************************************************
* dsTSTRING::dsTSTRING ()
*
*************************************************************/
//template <class CH> FORCE_INLINE dsTSTRING<CH>::dsTSTRING(const dsTSTRING &str, apSUPPRESS_PROCESSOR_LOCK) : pBuffer(NULL)
//{
//   UnsafeAttachBuffer(str.pBuffer);
//   return;
//}

/*************************************************************
* dsTSTRING::dsTSTRING ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH>::dsTSTRING(const CH *str, int len, int addLen) : pBuffer(NULL)
{
   AP_CHECK_CURRENT_PROCESSOR;
   UnsafeInit(str, len, addLen);
}

/*************************************************************
* dsTSTRING::dsTSTRING ()
*
*************************************************************/
//template <class CH> __INLINE dsTSTRING<CH>::dsTSTRING(const CH *str, apSUPPRESS_PROCESSOR_LOCK, int len, int addLen) : pBuffer(NULL)
//{
//   UnsafeInit(str, len, addLen);
//}

/******************************************************************************
* dsTSTRING<CH>::dsTSTRING
*
******************************************************************************/
template <class CH> __INLINE dsTSTRING<CH>::dsTSTRING(CH ch, int count) : pBuffer(NULL)
{
   pBuffer = UnsafeAllocBuffer(count, count);
   for (int i = 0; i < count; ++i) {
      pBuffer->str[i] = ch;
   }
}

/*************************************************************
* dsTSTRING::UnsafeInitEmpty()
*
*************************************************************/
#if defined _AP_PS3
template <> FORCE_INLINE void dsTSTRING<char>::UnsafeInitEmpty()
{
   extern dsTSTRING<char> emptyStr;
   pBuffer  = NULL;
   UnsafeAttachBuffer(emptyStr.pBuffer);
   return;
}

template <> FORCE_INLINE void dsTSTRING<wchar_t>::UnsafeInitEmpty()
{
   extern dsTSTRING<wchar_t> emptyWStr;
   pBuffer  = NULL;
   UnsafeAttachBuffer(emptyWStr.pBuffer);
   return;
}

#else
template <class CH> FORCE_INLINE void dsTSTRING<CH>::UnsafeInitEmpty()
{
   static dsTSTRING<CH> emptyStr(0);
   pBuffer  = NULL;
   UnsafeAttachBuffer(emptyStr.pBuffer);
   return;
}
#endif
/*************************************************************
* dsTSTRING::UnsafeInit()
*
*************************************************************/
template <class CH> __INLINE void dsTSTRING<CH>::UnsafeInit(const CH *str, int len, int addLen)
{
   pBuffer = NULL;
   if (!str && len) {
      dsTSTRING t;
      UnsafeAttachBuffer(t.pBuffer);
      return;
   }

   if (str[0] == 0 && addLen == 0) {
      dsTSTRING t;
      UnsafeAttachBuffer(t.pBuffer);
      return;
   }

   if (len == -1) {
      len = 0x7FFFFFFF;
   }

   // scan str range 0-len for \0 CH
   int i = 0;
   for (; i < len; i++) {
      if (!str[i]) {
         break;
      }
   }
   len = i;

   pBuffer = UnsafeAllocBuffer(len + addLen, len);
   memcpy(pBuffer->str, str, len * sizeof(CH));

   return;
}

/*************************************************************
* dsTSTRING::~dsTSTRING ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH>::~dsTSTRING(void)
{
   ReleaseBuffer(pBuffer);
   return;
}

/*************************************************************
* dsTSTRING::operator = ()
*
*************************************************************/
template <class CH> __INLINE const dsTSTRING<CH>& dsTSTRING<CH>::operator = (const dsTSTRING &str)
{
   if (&str != this) {
      ReleaseBuffer(pBuffer);
      AttachBuffer(str.pBuffer);
   }
   
   return *this;
}

/*************************************************************
* dsTSTRING::Clear ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH>& dsTSTRING<CH>::Clear(void)
{
   AP_CHECK_CURRENT_PROCESSOR;

   if (pBuffer->refCount == 1) {
      pBuffer->strLen = 0;
      pBuffer->str[pBuffer->strLen] = 0;
   } else {
      ReleaseBuffer(pBuffer);
      AttachBuffer(dsTSTRING().pBuffer);
   }
   return *this;
}

/*************************************************************
* dsTSTRING::SubStr ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH> dsTSTRING<CH>::SubStr(int pos, int len) const
{
   // check pos & len in range
   ASSERT(pos >=0 && pos <= pBuffer->strLen);
   if (len == -1) {
      len = pBuffer->strLen - pos;
   }
   if (len == 0) {
      return dsTSTRING<CH>();
   }
   ASSERT(pos + len <= pBuffer->strLen);
   // get substring
   return dsTSTRING<CH>(pBuffer->str + pos, len);
}

/*************************************************************
* dsTSTRING::ToUpper ()
*
*************************************************************/
template <class CH> __INLINE void dsTSTRING<CH>::ToUpper(void)
{
   AP_CHECK_CURRENT_PROCESSOR;

   if (pBuffer->refCount != 1) {
      BUFFER *oldBuf = pBuffer;
      pBuffer = AllocBuffer(oldBuf->strLen, oldBuf->strLen);
      memcpy(pBuffer->str, oldBuf->str, oldBuf->strLen * sizeof(CH));
      ReleaseBuffer(oldBuf);
   }

   for (int i = 0; i < Length(); i++) {
      pBuffer->str[i] = toupper(pBuffer->str[i]);
   }
   return;
}

/*************************************************************
* dsTSTRING::Upper ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH> dsTSTRING<CH>::Upper(void) const
{
   dsTSTRING<CH> str;
   str.Insert(0, *this);
   str.ToUpper();
   return str;
}

/*************************************************************
* dsTSTRING::ToLower ()
*
*************************************************************/
template <class CH> __INLINE void dsTSTRING<CH>::ToLower(void)
{
   AP_CHECK_CURRENT_PROCESSOR;

   if (pBuffer->refCount != 1) {
      BUFFER *oldBuf = pBuffer;
      pBuffer = AllocBuffer(oldBuf->strLen, oldBuf->strLen);
      memcpy(pBuffer->str, oldBuf->str, oldBuf->strLen * sizeof(CH));
      ReleaseBuffer(oldBuf);
   }

   for (int i = 0; i < Length(); i++) {
      pBuffer->str[i] = tolower(pBuffer->str[i]);
   }
   return;
}

/*************************************************************
* dsTSTRING::ToLower ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH> dsTSTRING<CH>::Lower(void) const
{
   dsTSTRING<CH> str;
   str.Insert(0, *this);
   str.ToLower();
   return str;
}

/*************************************************************
* dsTSTRING::EscForm ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH> dsTSTRING<CH>::EscForm(void)
{
   dsSTRING s;
   s.Reserve(Length());
   for (int i = 0; i < Length(); i++) {
      switch (At(i)) {
         case '"':
            s += "\\\"";
            break;
         case '\\':
            s += "\\\\";
            break;
         case '\n':
            s += "\\n";
            break;
         case '\r':
            s += "\\r";
            break;
         case '\t':
            s += "\\t";
            break;
         default:
            s += At(i);
            break;
      }
   }
   return s;
}

/*************************************************************
* dsTSTRING::EscForm ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH> dsTSTRING<CH>::UnEscForm(void)
{
   dsSTRING s;
   s.Reserve(Length());
   for (int i = 0; i < Length(); i++) {
      if (At(i) == '\\') {
         i++;
         switch (At(i)) {
            case '"':
               s += '"';
               break;
            case '\\':
               s += '\\';
               break;
            case '\n':
               s += '\n';
               break;
            case '\r':
               s += '\r';
               break;
            case '\t':
               s += '\t';
               break;
            default:
               s += '\\';
               s += At(i);
               break;
         }
      } else {
         s += At(i);
      }
   }
   return s;
}


/*************************************************************
* dsTSTRING::Erase ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH>& dsTSTRING<CH>::Erase(int pos, int len)
{
   AP_CHECK_CURRENT_PROCESSOR;

   // check pos & len in range
   ASSERT(pos >=0 && pos < pBuffer->strLen);
   if (len == -1 || len > pBuffer->strLen - pos) {
      len = pBuffer->strLen - pos;
   }

   // check if entire string deleted
   if (pos == 0 && len == pBuffer->strLen) {
      return Clear();
   }
   
   // delete string sectoin
   if (pBuffer->refCount == 1) {
      // unique buffer
      memmove(pBuffer->str + pos, pBuffer->str + pos + len, (pBuffer->strLen - (pos + len)) * sizeof(CH));
      pBuffer->strLen -= len;
      pBuffer->str[pBuffer->strLen] = 0;
   } else {
      // need to create new buffer
      BUFFER   *oldBuf = pBuffer;
      
      pBuffer = AllocBuffer(oldBuf->strLen - len, oldBuf->strLen - len);
      memcpy(pBuffer->str, oldBuf->str, pos * sizeof(CH));
      memcpy(pBuffer->str + pos, oldBuf->str + pos + len, (oldBuf->strLen - (pos + len)) * sizeof(CH));

      ReleaseBuffer(oldBuf);
   }

   return *this;
}

/*************************************************************
* dsTSTRING::Insert ()
*
*************************************************************/
template <class CH> __INLINE void dsTSTRING<CH>::Insert(int pos, int len)
{
   AP_CHECK_CURRENT_PROCESSOR;

   // check pos & len in range
   ASSERT(pos >=0 && pos <= pBuffer->strLen);
   ASSERT(len >=0);
   
   if (len == 0) {
      return;
   }

   // insert string section
   if (pBuffer->refCount == 1) {
      // unique buffer
      if (pBuffer->maxStrLen >= pBuffer->strLen + len) {
         // enough size - use old buffer
         pBuffer->strLen += len;
         pBuffer->str[pBuffer->strLen] = 0;
         memmove(pBuffer->str + pos + len, pBuffer->str + pos, (pBuffer->strLen - len - pos) * sizeof(CH));
      } else {
         // buffer need to grow
         pBuffer = ReallocBuffer(pBuffer, pBuffer->strLen + len, pBuffer->strLen + len);
         memmove(pBuffer->str + pos + len, pBuffer->str + pos, (pBuffer->strLen - len - pos) * sizeof(CH));
      }
   } else {
      // need to create new buffer
      BUFFER   *oldBuf = pBuffer;
      
      pBuffer = AllocBuffer(oldBuf->strLen + len, oldBuf->strLen + len);
      memcpy(pBuffer->str, oldBuf->str, pos * sizeof(CH));
      memcpy(pBuffer->str + pos + len, oldBuf->str + pos, (oldBuf->strLen - pos) * sizeof(CH));

      ReleaseBuffer(oldBuf);
   }

   return;
}

/*************************************************************
* dsTSTRING::Insert ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH>& dsTSTRING<CH>::Insert(int pos, const CH *str, int len)
{
   int   i;

   AP_CHECK_CURRENT_PROCESSOR;

   if (!str) {
      ASSERT(str || len == 0);
      len = 0;
   }
   // check pos in range
   ASSERT(pos >=0 && pos <= pBuffer->strLen);

   if (len == -1) {
      len = 0x7FFFFFFF;
   }
   
   // scan str range 0 - len for \0 CHs
   for (i = 0; i < len; i++) {
      if (!str[i]) {
         break;
      }
   }
   len = i;

   // insert string
   Insert(pos, len);
   memcpy(pBuffer->str + pos, str, len * sizeof(CH));

   return *this;
}

/*************************************************************
* dsTSTRING::Insert ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH>& dsTSTRING<CH>::Insert(int pos, const dsTSTRING &str)
{
   AP_CHECK_CURRENT_PROCESSOR;

   // check pos in range
   ASSERT(pos >=0 && pos <= pBuffer->strLen);
   
   // insert string
   Insert(pos, str.Length());
   memcpy(pBuffer->str + pos, str.CStr(), str.Length() * sizeof(CH));

   return *this;
}

/*************************************************************
* dsTSTRING::Reserve ()
*
*************************************************************/
template <class CH> __INLINE void dsTSTRING<CH>::Reserve(int strLen)
{
   AP_CHECK_CURRENT_PROCESSOR;

   if (pBuffer->maxStrLen >= strLen) {
      return;
   }

   if (pBuffer->refCount == 1) {
      // grow buffer
      pBuffer = ReallocBuffer(pBuffer, strLen, pBuffer->strLen);
   } else {
      // create new buffer
      BUFFER *oldBuf = pBuffer;

      pBuffer = AllocBuffer(strLen, oldBuf->strLen);
      memcpy(pBuffer->str, oldBuf->str, oldBuf->strLen * sizeof(CH));

      ReleaseBuffer(oldBuf);
   }

   return;
}

/*************************************************************
* dsTSTRING::Compact ()
*
*************************************************************/
template <class CH> __INLINE void dsTSTRING<CH>::Compact(bool noDup)
{
   AP_CHECK_CURRENT_PROCESSOR;

   if (pBuffer->maxStrLen == pBuffer->strLen) {
      // can't compact
      return;
   }

   if (Length() == 0) {
      ReleaseBuffer(pBuffer);
      AttachBuffer(dsTSTRING().pBuffer);
      return;
   }

   if (pBuffer->refCount == 1) {
      // change this buffer
      pBuffer = ReallocBuffer(pBuffer, pBuffer->strLen, pBuffer->strLen);
   } else if (!noDup) {
      // create new buffer
      BUFFER *oldBuf = pBuffer;

      pBuffer = AllocBuffer(oldBuf->strLen, oldBuf->strLen);
      memcpy(pBuffer->str, oldBuf->str, oldBuf->strLen * sizeof(CH));

      ReleaseBuffer(oldBuf);
   }

   return;
}

/*************************************************************
* dsTSTRING::Find()
*
*************************************************************/
template <class CH> __INLINE int dsTSTRING<CH>::Find(CH c, int start, BOOL noCase) const
{
   if (start < 0 || start >= Length()) {
      return -1;
   }
   if (noCase) {
      for (int i = start; i < Length(); i++) {
         if (tolower(pBuffer->str[i]) == tolower(c)) {
            return i;
         }
      }
   } else {
      for (int i = start; i < Length(); i++) {
         if (pBuffer->str[i] == c) {
            return i;
         }
      }
   }
   return -1;
}

/*************************************************************
* dsTSTRING::Find ()
*
*************************************************************/
template <class CH> __INLINE int dsTSTRING<CH>::Find(const CH *str, int start, BOOL noCase) const
{
   if (start < 0 || start >= Length() || !str) {
      return -1;
   }
   if (noCase) {
      for (int i = start; i < Length(); i++) {
         for (int j = 0; TRUE; j++) {
            if (str[j] == 0) {
               return i;
            }
            if (i + j >= Length()) {
               return -1;
            }
            if (tolower(pBuffer->str[i + j]) != tolower(str[j])) {
               break;
            }
         }
      }
   } else {
      for (int i = start; i < Length(); i++) {
         for (int j = 0; TRUE; j++) {
            if (str[j] == 0) {
               return i;
            }
            if (i + j >= Length()) {
               return -1;
            }
            if (pBuffer->str[i + j] != str[j]) {
               break;
            }
         }
      }
   }
   return -1;
}

/*************************************************************
* dsTSTRING::Find ()
*
*************************************************************/
template <class CH> __INLINE int dsTSTRING<CH>::Find(const dsTSTRING<CH> &str, int start, BOOL noCase) const
{
   return Find(str.CStr(), start, noCase);
}

/*************************************************************
* dsTSTRING::RFind()
*
*************************************************************/
template <class CH> __INLINE int dsTSTRING<CH>::RFind(CH c, int start, BOOL noCase) const
{
   if (start == -1) {
      start = Length() - 1;
   }
   if (start < 0 || start >= Length()) {
      return -1;
   }
   if (noCase) {
      for (int i = start; i >= 0; i--) {
         if (tolower(pBuffer->str[i]) == tolower(c)) {
            return i;
         }
      }
   } else {
      for (int i = start; i >= 0; i--) {
         if (pBuffer->str[i] == c) {
            return i;
         }
      }
   }
   return -1;
}

/*************************************************************
* dsTSTRING::RFind()
*
*************************************************************/
template <class CH> __INLINE int dsTSTRING<CH>::RFind(const CH* str, int start, BOOL noCase) const
{
   if (start == -1) {
      start = Length() - 1;
   }
   if (!str || start < 0 || start >= Length()) {
      return -1;
   }

   if (noCase) {
      for (int i = start; i >= 0; i--) {
         for (int j = 0; TRUE; j++) {
            if (str[j] == 0) {
               return i;
            }
            if (i + j >= Length()) {
               break;
            }
            if (tolower(pBuffer->str[i + j]) != tolower(str[j])) {
               break;
            }
         }
      }
   } else {
      for (int i = start; i >= 0; i--) {
         for (int j = 0; TRUE; j++) {
            if (str[j] == 0) {
               return i;
            }
            if (i + j >= Length()) {
               break;
            }
            if (pBuffer->str[i + j] != str[j]) {
               break;
            }
         }
      }
   }
   return -1;
}

/*************************************************************
* dsTSTRING::Insert ()
*
*************************************************************/
template <class CH> __INLINE dsTSTRING<CH>& dsTSTRING<CH>::Insert(int pos, CH c, int num)
{
   AP_CHECK_CURRENT_PROCESSOR;

   // check pos in range
   ASSERT(pos >=0 && pos <= pBuffer->strLen);
   
   // insert CHs
   Insert(pos, num);
   for (int i = 0; i < num; i++) {
      pBuffer->str[pos + i] = c;
   }

   return *this;
}

/*************************************************************
* dsTSTRING::Lock ()
*
*************************************************************/
template <class CH> __INLINE CH* dsTSTRING<CH>::Lock(int strLen)
{
   AP_CHECK_CURRENT_PROCESSOR;

   if (pBuffer->refCount == 1) {
      // grow buffer
      if (pBuffer->maxStrLen < strLen) {
         pBuffer = ReallocBuffer(pBuffer, strLen, pBuffer->strLen);
      }
   } else {
      // create new buffer
      BUFFER *oldBuf = pBuffer;

      pBuffer = AllocBuffer(strLen, oldBuf->strLen);
      memcpy(pBuffer->str, oldBuf->str, oldBuf->strLen * sizeof(CH));

      ReleaseBuffer(oldBuf);
   }

   if (strLen < pBuffer->strLen) {
      pBuffer->strLen = strLen;
   }
   pBuffer->str[strLen] = 0;

   return pBuffer->str;
}

/*************************************************************
* dsTSTRING::Lock ()
*
*************************************************************/
template <class CH> __INLINE CH& dsTSTRING<CH>::At(int idx)
{
   AP_CHECK_CURRENT_PROCESSOR;

   if (pBuffer->refCount != 1) {
      BUFFER *oldBuf = pBuffer;
      pBuffer = AllocBuffer(oldBuf->strLen, oldBuf->strLen);
      memcpy(pBuffer->str, oldBuf->str, oldBuf->strLen * sizeof(CH));
      ReleaseBuffer(oldBuf);
   }
   ASSERT(idx >= 0 && idx <= pBuffer->strLen);
   return pBuffer->str[idx];
}

/*************************************************************
* dsTSTRING::Unlock ()
*
*************************************************************/
template <class CH> __INLINE void dsTSTRING<CH>::Unlock(void)
{
   AP_CHECK_CURRENT_PROCESSOR;

   for (int i = 0; i <= pBuffer->maxStrLen; i++) {
      if (pBuffer->str[i] == 0) {
         pBuffer->strLen = i;
         return;
      }
   }
   pBuffer->strLen = pBuffer->maxStrLen;
   pBuffer->str[pBuffer->strLen] = 0;
   return;
}

/*************************************************************
* dsTSTRING::AttachBuffer ()
*
*************************************************************/
template <class CH> FORCE_INLINE void dsTSTRING<CH>::AttachBuffer(const BUFFER *pBuf)
{
   AP_CHECK_CURRENT_PROCESSOR;
   UnsafeAttachBuffer(pBuf);
}

/*************************************************************
* dsTSTRING::UnsafeAttachBuffer ()
*
*************************************************************/
template <class CH> FORCE_INLINE void dsTSTRING<CH>::UnsafeAttachBuffer(const BUFFER *pBuf)
{
   // check for simultaneous access (addref/release) from different threads
   //STRONG_ASSERT(pBuf->maxStrLen == 0 || osLockedIncrement((int*)&pBuf->locked) == 1);
   pBuffer = const_cast<BUFFER*>(pBuf);
   pBuffer->refCount++;
   //STRONG_ASSERT(pBuf->maxStrLen == 0 || osLockedDecrement((int*)&pBuf->locked) == 0);
   return;
}

/*************************************************************
* dsTSTRING::GetBufMemSize ()
*
*************************************************************/
template <class CH> __INLINE int dsTSTRING<CH>::GetBufMemSize(int len)
{
   int size = sizeof(BUFFER) + len * sizeof(CH);
   // align size to 16 (std MSVC heap blocks will do this anyway)
//   size = (size + 15) >> 4 << 4;
   return size;
}

/*************************************************************
* dsTSTRING::GetBufMemSize ()
*
*************************************************************/
template <class CH> __INLINE int dsTSTRING<CH>::GetStrLenFromMem(int size)
{
   return (size - sizeof(BUFFER)) / sizeof(CH);
}

/*************************************************************
* dsTSTRING::AllocBuffer ()
*
*************************************************************/
template <class CH> __INLINE typename dsTSTRING<CH>::BUFFER* dsTSTRING<CH>::AllocBuffer(int maxLen, int len)
{
   AP_CHECK_CURRENT_PROCESSOR;
   return UnsafeAllocBuffer(maxLen, len);
}

/*************************************************************
* dsTSTRING::UnsafeAllocBuffer ()
*
*************************************************************/
template <class CH> __INLINE typename dsTSTRING<CH>::BUFFER* dsTSTRING<CH>::UnsafeAllocBuffer(int maxLen, int len)
{
   if (maxLen < len) {
      maxLen = len;
   }
   
   int mem = GetBufMemSize(maxLen);
   // alloc buffer
   BUFFER *pBuf = (BUFFER*)malloc(mem);
#ifdef USE_CALLSTACK_STAT
   apDlStatCallstackNotifyAdd("string", pBuf, mem);
#endif
  
   //pBuf->locked   = 0;
   pBuf->refCount = 1;
   pBuf->strLen = len;
   pBuf->maxStrLen = GetStrLenFromMem(mem);
   ASSERT(pBuf->maxStrLen >= pBuf->strLen);
#ifdef __PLUGIN__
   pBuf->deleter = &BUFFER::Realloc;
#endif
   pBuf->str[pBuf->strLen] = 0;

   return pBuf;
}

/*************************************************************
* dsTSTRING::ReallocBuffer ()
*
*************************************************************/
template <class CH> __INLINE typename dsTSTRING<CH>::BUFFER* dsTSTRING<CH>::ReallocBuffer(BUFFER *pBuf, int maxLen, int len)
{
   AP_CHECK_CURRENT_PROCESSOR;

   if (maxLen < len) {
      maxLen = len;
   }

   int mem = GetBufMemSize(maxLen);
   // realloc buffer
#ifdef __PLUGIN__
   if (pBuf != NULL) {
      BUFFER::DELETER deleter = pBuf->deleter;
      pBuf = (BUFFER *)(pBuf->*deleter)(pBuf, mem);
      pBuf->deleter = deleter;
   } else {
      pBuf = (BUFFER *)malloc(mem);
      pBuf->deleter = &BUFFER::Realloc;
   }
#else
   #ifdef USE_CALLSTACK_STAT
      apDlStatCallstackNotifyRemove("string", pBuf);
   #endif
   
   pBuf = (BUFFER *)realloc(pBuf, mem);

   #ifdef USE_CALLSTACK_STAT
      apDlStatCallstackNotifyAdd("string", pBuf, mem);
   #endif
#endif
  

   pBuf->refCount = 1;
   pBuf->strLen = len;
   pBuf->maxStrLen = GetStrLenFromMem(mem);
   ASSERT(pBuf->maxStrLen >= pBuf->strLen);
   pBuf->str[pBuf->strLen] = 0;

   return pBuf;
}

/*************************************************************
* dsTSTRING::ReleaseBuffer ()
*
*************************************************************/
template <class CH> __INLINE void dsTSTRING<CH>::ReleaseBuffer(BUFFER *pBuf)
{
   //STRONG_ASSERT(pBuf->maxStrLen == 0 || osLockedIncrement(&pBuf->locked) == 1);
   AP_CHECK_CURRENT_PROCESSOR;

   ASSERT(pBuf->refCount);
   pBuf->refCount--;
   if (pBuf->refCount == 0) {
      //STRONG_ASSERT(pBuf->maxStrLen == 0 || osLockedDecrement(&pBuf->locked) == 0);

#ifndef __PLUGIN__
      #ifdef USE_CALLSTACK_STAT
         apDlStatCallstackNotifyRemove("string", pBuf);
      #endif
      free(pBuf);
#else
      void * res = (pBuf->*(pBuf->deleter))(pBuf, 0);
      STRONG_ASSERT(res == NULL);
#endif
   } else {
      //STRONG_ASSERT(pBuf->maxStrLen == 0 || osLockedDecrement(&pBuf->locked) == 0);
   }
   return;
}

/*************************************************************
* dsTSTRING::operator == ()
*
*************************************************************/
template <class CH> __INLINE bool dsTSTRING<CH>::operator == (const dsTSTRING &str) const
{
   if (pBuffer == str.pBuffer) {
      return TRUE;
   }
   if (pBuffer->strLen != str.pBuffer->strLen) {
      return FALSE;
   }
   if (pBuffer->strLen == 0) {
      return TRUE;
   }

   return memcmp(pBuffer->str, str.pBuffer->str, pBuffer->strLen * sizeof(CH)) == 0;
   //return strcmp(pBuffer->str, str.pBuffer->str) == 0;
}

/*************************************************************
* dsTSTRING::operator == ()
*
*************************************************************/
template <class CH> __INLINE bool dsTSTRING<CH>::operator == (const CH *str) const
{
   return strcmp(pBuffer->str, str) == 0;
}

/*************************************************************
* dsTSTRING::operator != ()
*
*************************************************************/
template <class CH> __INLINE bool dsTSTRING<CH>::operator != (const dsTSTRING &str) const
{
   return !(*this == str);
}

/*************************************************************
* dsTSTRING::operator != ()
*
*************************************************************/
template <class CH> __INLINE bool dsTSTRING<CH>::operator != (const CH *str) const
{
   return !(*this == str);
}

/*************************************************************
* dsTSTRING::operator > ()
*
*************************************************************/
template <class CH> __INLINE bool dsTSTRING<CH>::operator > (const dsTSTRING &other) const
{
   return (*this) > (other.pBuffer->str);
}

/*************************************************************
* dsTSTRING::operator > ()
*
*************************************************************/
template <class CH> __INLINE bool dsTSTRING<CH>::operator > (const CH *other) const
{
   return strcmp(pBuffer->str, other) > 0;
}

/*************************************************************
* dsTSTRING::operator < ()
*
*************************************************************/
template <class CH> __INLINE bool dsTSTRING<CH>::operator < (const dsTSTRING &other) const
{
   return (*this) < (other.pBuffer->str);
}

/*************************************************************
* dsTSTRING::operator < ()
*
*************************************************************/
template <class CH> __INLINE bool dsTSTRING<CH>::operator < (const CH *other) const
{
   return strcmp(pBuffer->str, other) < 0;
}

/*************************************************************
* dsTSTRING::operator >= ()
*
*************************************************************/
template <class CH> __INLINE bool dsTSTRING<CH>::operator >= (const dsTSTRING &other) const
{
   return (*this) >= (other.pBuffer->str);
}

/*************************************************************
* dsTSTRING::operator > ()
*
*************************************************************/
template <class CH> __INLINE bool dsTSTRING<CH>::operator >= (const CH *other) const
{
   return strcmp(pBuffer->str, other) >= 0;
}

/*************************************************************
* dsTSTRING::operator < ()
*
*************************************************************/
template <class CH> __INLINE bool dsTSTRING<CH>::operator <= (const dsTSTRING &other) const
{
   return (*this) <= (other.pBuffer->str);
}

/*************************************************************
* dsTSTRING::operator < ()
*
*************************************************************/
template <class CH> __INLINE bool dsTSTRING<CH>::operator <= (const CH *other) const
{
   return strcmp(pBuffer->str, other) <= 0;
}

/**************************************************************************
* CH> inline void dsTSTRING<CH>::Trim()                                   *
*                                                                         *
**************************************************************************/
template <class CH>
__INLINE void dsTSTRING<CH>::Trim(void)
{
	bool found = false;

	int first = 0;
	for (; first<Length(); ++first) {
		if ((BYTE)(*this)[first] > ' ') {
			break;
		}
	}

	int last = Length() - 1;
	for (; last > first; --last) {
		if ((BYTE)(*this)[last] > ' ') {
			break;
		}
	}

	*this = SubStr(first, last - first + 1);
}

/******************************************************************************
* dsTSTRING<CH>::TrimRight
*
******************************************************************************/
template <class CH>
inline void dsTSTRING<CH>::TrimRight(void)
{
   int right = Length() - 1;
   while (right >= 0 && (*this)[right] <= ' ') {
      --right;
   }

   if (right < 0) {
      Clear();
      return ;
   }

   *this = SubStr(0, right + 1);
}

/******************************************************************************
* dsTSTRING<CH>::TrimLeft
*
******************************************************************************/
template <class CH>
inline void dsTSTRING<CH>::TrimLeft(void)
{
   int left = 0;
   while (left < Length() && (*this)[left] <= ' ') {
      ++left;
   }

   if (left >= Length()) {
      Clear();
      return ;
   }

   *this = SubStr(left, Length() - left);
}

/*************************************************************************
* dsTSTRING<CH>::IsStartWith 
*
*************************************************************************/
template <class CH>
__INLINE bool dsTSTRING<CH>::IsStartWith(const CH* s, bool noCase, int ofs) const
{
   for (int pos = ofs; pos < Length(); pos++, s++) {
      if (*s == 0) {
         return true;
      }
      if (noCase) {
         if (tolower(*s) != tolower(pBuffer->str[pos])) {
            return false;
         }
      } else {
         if (*s != pBuffer->str[pos]) {
            return false;
         }
      }
   }
   if (*s == 0) {
      return true;
   }
   return false;
}

/*************************************************************************
* dsTSTRING<CH>::IsEndWith 
*
*************************************************************************/
template <class CH> 
__INLINE bool dsTSTRING<CH>::IsEndWith(const CH *s, bool noCase) const
{
   int start = Length() - 1;

   int l;
   for (l = 0; l < INT_MAX; l++) {
      if (s[l] == 0) {
         break;
      }
   }

   if (l > Length()) {
      return false;
   }

   if (noCase) {
      for (int i = 0; i < l; i++) {
         if (tolower(s[i]) != tolower(pBuffer->str[pBuffer->strLen - l + i])) {
            return false;
         }
      }
   } else {
      for (int i = 0; i < l; i++) {
         if (s[i] != pBuffer->str[pBuffer->strLen - l + i]) {
            return false;
         }
      }
   }
   return true;
}

/*************************************************************************
* dsTSTRING<CH>::Replace 
*
*************************************************************************/
template <class CH>
__INLINE int dsTSTRING<CH>::Replace(const dsTSTRING<CH> & key, const dsTSTRING<CH> & value)
{
   int index = Find(key);
   if (index == -1) {
      return 0;
   }

   int count = 0;

   dsTSTRING<CH> res;
   int start = 0;
   do {
      ++count;
      res += SubStr(start, index - start);
      res += value;

      start = index + key.Length();
      index = Find(key, start);
   } while (index != -1);

   res += SubStr(start, -1);

   *this = res;
   return count;
}

/******************************************************************************
* dsTSTRING<CH>::LJust
*
******************************************************************************/
template <class CH>
inline dsTSTRING<CH> dsTSTRING<CH>::LJust(int width) const
{
   int toAdd = max(0, width - this->Length());
   return *this + dsTSTRING(' ', toAdd);
}

template <class CH>
inline dsTSTRING<CH> dsTSTRING<CH>::RJust(int width) const
{
   int toAdd = max(0, width - this->Length());
   return dsTSTRING(' ', toAdd) + *this;
}

struct ARG_ESCAPE_DATA
{
   int min_escape;
   int occurrences;
   int escape_len;
};

ARG_ESCAPE_DATA dsStrFindArgEscapes(const dsSTRING &s);
dsSTRING dsStrReplaceArgEscapes(const dsSTRING &s, const ARG_ESCAPE_DATA &d, int field_width, const dsSTRING &arg, char fillChar);

template<> __INLINE dsSTRING dsSTRING::Arg(const dsSTRING &a, int fieldWidth, char fillChar) const
{
   ARG_ESCAPE_DATA d = dsStrFindArgEscapes(*this);

   if (d.occurrences == 0) {
      return *this;
   }

   return dsStrReplaceArgEscapes(*this, d, fieldWidth, a, fillChar);
}

template<> __INLINE dsSTRING dsSTRING::Arg(char a, int fieldWidth, char fillChar) const
{
   dsSTRING c;
   c+=a;
   return Arg(c, fieldWidth, fillChar);
}

template<> __INLINE dsSTRING dsSTRING::Arg(float a, int fieldWidth, int prec, char fmt, char fillChar) const
{
   ARG_ESCAPE_DATA d = dsStrFindArgEscapes(*this);

   if (d.occurrences == 0) {
      return *this;
   }

   dsSTRING format;
   if ( prec == -1 ) {
      format = dsSPrintf("%%%c", fmt);
   } else {
      format = dsSPrintf("%%.%d%c", prec, fmt);
   }

   dsSTRING arg = dsSPrintf(format.CStr(), a);

   return dsStrReplaceArgEscapes(*this, d, fieldWidth, arg, fillChar);
}

template<> __INLINE dsSTRING dsSTRING::Arg(int a, int fieldWidth, char fmt, char fillChar) const
{
   ARG_ESCAPE_DATA d = dsStrFindArgEscapes(*this);

   if (d.occurrences == 0) {
      return *this;
   }

   dsSTRING format = dsSPrintf("%%%c", fmt);

   dsSTRING arg = dsSPrintf(format.CStr(), a);

   return dsStrReplaceArgEscapes(*this, d, fieldWidth, arg, fillChar);
}

template<> __INLINE dsSTRING dsSTRING::Arg(UINT a, int fieldWidth, char fmt, char fillChar) const
{
   ARG_ESCAPE_DATA d = dsStrFindArgEscapes(*this);

   if (d.occurrences == 0) {
      return *this;
   }

   dsSTRING format = dsSPrintf("%%%c", fmt);

   dsSTRING arg = dsSPrintf(format.CStr(), a);

   return dsStrReplaceArgEscapes(*this, d, fieldWidth, arg, fillChar);
}
